package com.example.demo.utils;

import com.jcraft.jsch.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

/**
 * @author Liunh
 */
@Slf4j
public class JschUtil {

    /**
     * 主机ip
     */
    private List<String> hostList;
    /**
     * 主机端口号
     */
    private int port;
    /**
     * 主机账号
     */
    private String username;
    /**
     * 主机密码
     */
    private String password;

    private JschUtil() {
    }

    public JschUtil(String host, int port, String username, String password) {
        if (StringUtils.isNotBlank(host)) {
            this.hostList = new ArrayList<>();
            this.hostList.add(host);
        }
        this.port = port;
        this.username = username;
        this.password = password;
    }

    public JschUtil(List<String> hostList, int port, String username, String password) {
        this.hostList = hostList;
        this.port = port;
        this.username = username;
        this.password = password;
    }

    /**
     * 检测是否可以和主机通信
     *
     * @return
     */
    public boolean connect() {
        Session session = null;
        boolean isConnected = false;
        try {
            if (CollectionUtils.isNotEmpty(hostList)) {
                for (String host : hostList) {
                    session = new JSch().getSession(username, host, port);
                    session.setPassword(password);
                    Properties config = new Properties();
                    config.put("StrictHostKeyChecking", "no");
                    session.setConfig(config);
                    session.setTimeout(3000);
                    session.connect();
                    isConnected = session.isConnected();
                    if (!isConnected) {
                        log.error(">>>>>> 获取连接失败! host = {}", host);
                    }
                }
            }
        } catch (JSchException e) {
            log.warn(e.getMessage());
        } finally {
            this.close(session, null, null);
        }
        return isConnected;
    }

    /**
     * 执行shell命令
     *
     * @param command
     * @return
     */
    public String execCommand(String command) {
        Session session = null;
        ChannelSftp chSftp = null;
        Channel channel = null;
        StringBuffer result = new StringBuffer();
        int exitStatus = 0;
        try {
            if (CollectionUtils.isNotEmpty(hostList)) {
                for (String host : hostList) {
                    session = new JSch().getSession(username, host, port);
                    session.setPassword(password);
                    Properties config = new Properties();
                    config.put("StrictHostKeyChecking", "no");
                    session.setConfig(config);
                    session.setTimeout(3000);
                    session.connect();
                    channel = session.openChannel("exec");
                    ((ChannelExec) channel).setCommand(command);
                    channel.setInputStream(null);
                    ((ChannelExec) channel).setErrStream(System.err);
                    channel.connect();
                    InputStream in = channel.getInputStream();
                    byte[] tmp = new byte[1024];
                    while (true) {
                        while (in.available() > 0) {
                            int i = in.read(tmp, 0, 1024);
                            if (i < 0) {
                                break;
                            }
                            result.append(new String(tmp, 0, i));
                        }
                        if (channel.isClosed()) {
                            if (in.available() > 0) {
                                continue;
                            }
                            exitStatus = channel.getExitStatus();
                            break;
                        }
                        Thread.sleep(3000);
                    }
                }
            }
        } catch (IOException | JSchException | InterruptedException e) {
            log.error(e.getMessage());
        } finally {
            this.close(session, channel, chSftp);
        }
        log.info("退出码为：" + exitStatus);
        return result.toString();
    }

    /**
     * 文件上传至主机
     *
     * @param directory  要上传的文件路径
     * @param uploadFile 上传保存的路径
     */
    public void upload(String directory, String uploadFile) {
        Session session = null;
        ChannelSftp chSftp = null;
        try {
            if (CollectionUtils.isNotEmpty(hostList)) {
                for (String host : hostList) {
                    session = new JSch().getSession(username, host, port);
                    session.setPassword(password);
                    Properties config = new Properties();
                    config.put("StrictHostKeyChecking", "no");
                    session.setConfig(config);
                    session.setTimeout(3000);
                    session.connect();
                    chSftp = (ChannelSftp) session.openChannel("sftp");
                    chSftp.connect();
                    chSftp.setFilenameEncoding(StandardCharsets.UTF_8);
                    chSftp.put(directory, uploadFile);
                    Thread.sleep(3000);
                    log.info("文件上传成功! host = {}, file = {}", host, directory.substring(directory.lastIndexOf("/"), directory.length()));
                }
            }
        } catch (JSchException | SftpException | InterruptedException e) {
            log.warn(e.getMessage());
        } finally {
            this.close(session, null, chSftp);
        }
    }

    /**
     * 将主机文件下载至本地
     *
     * @param directory    要下载的文件位置
     * @param downloadFile 下载文件待保存的位置
     */
    public void download(String directory, String downloadFile) {
        Session session = null;
        ChannelSftp chSftp = null;
        try {
            if (CollectionUtils.isNotEmpty(hostList)) {
                for (String host : hostList) {
                    session = new JSch().getSession(username, host, port);
                    session.setPassword(password);
                    Properties config = new Properties();
                    config.put("StrictHostKeyChecking", "no");
                    session.setConfig(config);
                    session.setTimeout(3000);
                    session.connect();
                    chSftp = (ChannelSftp) session.openChannel("sftp");
                    chSftp.connect();
                    chSftp.setFilenameEncoding(StandardCharsets.UTF_8);
                    chSftp.get(directory, downloadFile);
                    Thread.sleep(3000);
                    log.info("文件下载成功! host = {}, file = {}", host, directory.substring(directory.lastIndexOf("/"), directory.length()));
                }
            }
        } catch (JSchException | SftpException | InterruptedException e) {
            log.warn(e.getMessage());
        } finally {
            this.close(session, null, chSftp);
        }
    }

    /**
     * 关闭连接
     */
    private void close(Session session, Channel channel, ChannelSftp chSftp) {
        if (channel != null && channel.isConnected()) {
            channel.disconnect();
        }
        if (session != null && session.isConnected()) {
            session.disconnect();
        }
        if (chSftp != null && chSftp.isConnected()) {
            chSftp.quit();
        }
    }
}
